package com.higgins.client.knowledge;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;


public class KnowledgeTree extends Tree implements Refreshable	{
	private final KnowledgeServiceAsync knowledgeService = GWT
	.create(KnowledgeService.class);
	private List<TreeListener> treeListeners = new ArrayList<TreeListener>();
	private Long parentId = null;
	private List<Long> parentIds = null;
	private String level = null;
	
	public KnowledgeTree(String level)	{
		this.level = level;
	}
	
	public void initialise()	{
		addHandlers();
		loadInitialTreeItems();
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void addHandlers()	{
		addSelectionHandler(new SelectionHandler()	{
			@Override
			public void onSelection(SelectionEvent event) {
				TreeItem itemSelected = (TreeItem) event.getSelectedItem();
				System.out.println("Tree Item Selected = " + itemSelected.getUserObject());
				
				if (treeListeners.size() > 0)	{
					updateTreeListeners(itemSelected);
				} 
			}
		});
		addOpenHandler(new OpenHandler()	{
			@Override
			public void onOpen(OpenEvent event) {
				TreeItem itemOpened = (TreeItem) event.getTarget();
				System.out.println("Tree Item Opened = " + itemOpened.getUserObject());
				itemOpened(itemOpened);
			}
		});
			
	}
	private void updateTreeListeners(TreeItem treeItem)	{
		KnowledgeItemDTO parent = (KnowledgeItemDTO)treeItem.getUserObject();
		parentId = parent.getId();
		List<KnowledgeItemDTO> knowledgeItems = new ArrayList<KnowledgeItemDTO>();
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			knowledgeItems.add((KnowledgeItemDTO)childTreeItem.getUserObject());
		}
		updateTreeListeners(knowledgeItems);
	}
	
	private void updateTreeListeners(List<KnowledgeItemDTO> knowledgeItems)	{
		for (TreeListener treeListener:treeListeners)	{
			treeListener.update(knowledgeItems);
			treeListener.setParentId(parentId);
		}
	}
	
	@SuppressWarnings("unused")
	private void loadInitialTreeItems()	{
		loadParentTreeItems();
	}
	private void loadParentTreeItems()	{
		knowledgeService.retrieveKnowledgeItems(level, null, new AsyncCallback<List<KnowledgeItemDTO>>()	{

			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<KnowledgeItemDTO> result) {
				addTreeParent(result);

				for (int count=0; count < getItemCount(); count++)	{
					TreeItem parent = getItem(count);
					loadChildren(parent);
				}
				openTreeAtParentId();
			}
		});
	}
	private void loadChildren(TreeItem parent)	{
		Long parentId = getId(parent);
		knowledgeService.retrieveKnowledgeItems(level, parentId, new AsyncCallback<List<KnowledgeItemDTO>>()	{

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onSuccess(List<KnowledgeItemDTO> dataItems) {
				addTreeItems(dataItems);
			}
			
		});
	}
	private void itemOpened(TreeItem parentTreeItem)	{
		System.out.println("Child Count = " + parentTreeItem.getChildCount());
		for (int childIndex = 0; childIndex < parentTreeItem.getChildCount(); childIndex++)	{
			TreeItem childTreeItem = parentTreeItem.getChild(childIndex);
			loadChildren(childTreeItem);
		}
	}
	
	private Long getId(TreeItem parent)	{
		KnowledgeItemDTO parentItem = (KnowledgeItemDTO) parent.getUserObject();
		return parentItem.getId();
	}
	private void addTreeParent(List<KnowledgeItemDTO> items)	{
		for (KnowledgeItemDTO item:items)	{
			TreeItem treeItem = new TreeItem(item.getItem());
			treeItem.setUserObject(item);
//			treeItem.setState(true);
			addItem(treeItem);
		}
	}
	private void addTreeItems(List<KnowledgeItemDTO> knowledgeItems)	{
		for (KnowledgeItemDTO knowledgeItem:knowledgeItems)
			addTreeItem(knowledgeItem);
	}
	private void addTreeItem(KnowledgeItemDTO knowledgeItem)	{
		TreeItem parent = findParent(knowledgeItem.getParentId()); 
		if (parent!=null)	{
			TreeItem treeItem = new TreeItem(knowledgeItem.getItem());
			treeItem.setUserObject(knowledgeItem);
//			treeItem.setState(true);
			parent.addItem(treeItem);
//			parent.setState(true);
		}
	}
	private TreeItem findParent(Long parentId)	{
		Iterator<TreeItem> treeIterator = treeItemIterator();
		while (treeIterator.hasNext())	{
			TreeItem treeItem = treeIterator.next();
			KnowledgeItemDTO dto = (KnowledgeItemDTO) treeItem.getUserObject();
			if (parentId.equals(dto.getId()))
				return treeItem;
			
			TreeItem foundTreeItem =  checkForParentId(treeItem, parentId);
			if (foundTreeItem != null)
				return foundTreeItem;
		}
		return null;
	}
	
	private TreeItem checkForParentId(TreeItem treeItem, Long parentId)	{
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			KnowledgeItemDTO childDto = (KnowledgeItemDTO) childTreeItem.getUserObject();
			if (parentId.equals(childDto.getId()))
				return childTreeItem;
//			return checkForParentId(childTreeItem, parentId);
		}
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			TreeItem foundTreeItem = checkForParentId(childTreeItem, parentId);
			if (foundTreeItem != null)
				return foundTreeItem;
		}		
		return null;
	}
	
/*
	private TreeItem checkForParentIdTwo(TreeItem treeItem, Long parentId)	{
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			ProjectItemDTO childDto = (ProjectItemDTO) childTreeItem.getUserObject();
			if (parentId.equals(childDto.getId()))
				return childTreeItem;
//			return checkForParentId(childTreeItem, parentId);
		}
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			return checkForParentIdThree(childTreeItem, parentId);
		}		
		return null;
	}
	
	private TreeItem checkForParentIdThree(TreeItem treeItem, Long parentId)	{
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			ProjectItemDTO childDto = (ProjectItemDTO) childTreeItem.getUserObject();
			if (parentId.equals(childDto.getId()))
				return childTreeItem;
//			return checkForParentId(childTreeItem, parentId);
		}
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			return checkForParentIdFour(childTreeItem, parentId);
		}		
		return null;
	}	
	
	private TreeItem checkForParentIdFour(TreeItem treeItem, Long parentId)	{
		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
			TreeItem childTreeItem = treeItem.getChild(childCount);
			ProjectItemDTO childDto = (ProjectItemDTO) childTreeItem.getUserObject();
			if (parentId.equals(childDto.getId()))
				return childTreeItem;
//			return checkForParentId(childTreeItem, parentId);
		}
//		for (int childCount = 0; childCount < treeItem.getChildCount(); childCount++)	{
//			TreeItem childTreeItem = treeItem.getChild(childCount);
//			return checkForParentIdfive(childTreeItem, parentId);
//		}		
		return null;
	}		
	*/
	public void addTreeListener(TreeListener treeListener)	{
		treeListeners.add(treeListener);
	}
	private void loadSelectedItem()	{
		knowledgeService.retrieveKnowledgeItems(level, parentId, new AsyncCallback<List<KnowledgeItemDTO>>()	{
			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<KnowledgeItemDTO> dataItems) {
				updateTreeListeners(dataItems);
				updateSelectedTreeItem(dataItems);
			}
		});
	}
	private void updateSelectedTreeItem(List<KnowledgeItemDTO> dataItems)	{
		TreeItem parent = findParent(parentId);
		int count = 1;
		for (KnowledgeItemDTO knowledgeItemDTO:dataItems)	{
			if (count > parent.getChildCount())	{
				addTreeItem(knowledgeItemDTO);
			} else {
				TreeItem treeItem = parent.getChild(count-1);
				treeItem.setUserObject(knowledgeItemDTO);
				treeItem.setText(knowledgeItemDTO.getItem());
			}
			count++;
		}
	}
	private void openTreeAtParentId()	{
//		TreeItem parent = findParent(28l); 
//		parent.setState(true);
//		for (int i = 0; i < this.getItemCount(); i++)	{
//			TreeItem item = this.getItem(i);
//			ProjectItemDTO projItem = (ProjectItemDTO)item.getUserObject();
//			Long id = projItem.getId();
//			if (id.equals(parendId))
//				item.setState(true);
//		}
	}
	@Override
	public void refresh() {
		clear();
		loadInitialTreeItems();
	}
	@Override
	public void refreshSelectedOnly() {
		loadSelectedItem();
	}
}
